﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Web;
using C5;
using RegexTools;

namespace WebFramework
{
    public class RequestHandler : IHttpHandler
    {
        #region Options
        Route[] GeneralRoutes = new Route[] {
            //new Route(@"/user:(?<id>\d+)", "UserController.View")
        };

        bool StripLeadingSlash = false;
        bool StripTrailingSlash = true;
        bool UseRelativePath = true;
        #endregion

        private IntervalHeap<Route> _routes = new IntervalHeap<Route>();

        private static IEnumerable<Route> GetInlineRoutes()
        {
            var methods = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a =>
                    a.GetTypes()
                        .Where(t => t.IsClass && t.IsSubclassOf(typeof (Controller))))
                .SelectMany(c => c.GetMethods(BindingFlags.Public | BindingFlags.Instance));

            return from method in methods
                let urlAttributes = method.GetCustomAttributes(true).OfType<UrlAttribute>()
                from attr in urlAttributes
                select new Route(attr.Pattern, method, attr.Priority);
        }

        private string GetRequestPath(HttpRequest request)
        {
            var requestPath = UseRelativePath ? request.AppRelativeCurrentExecutionFilePath.Substring(1) : request.Path;

            if (StripLeadingSlash)
                requestPath = StripTrailingSlash ? requestPath.Trim('/') : requestPath.TrimStart('/');
            else if (StripTrailingSlash)
                requestPath = requestPath.TrimEnd('/');

            return requestPath;
        }

        public RequestHandler()
        {
            _routes.AddAll(GetInlineRoutes());
            _routes.AddAll(GeneralRoutes);
        }

        public void ProcessRequest(HttpContext context)
        {
            var requestPath = GetRequestPath(context.Request);
            Debug.WriteLine(string.Format("Request Path: {0}", requestPath));

            foreach (var route in _routes)
            {
                if (!route.IsMatch(requestPath)) continue;
                Debug.WriteLine("Route: {0}", route);
                var result = route.Execute(requestPath);
                result.Render(context.Response);
                break;
            }
        }

        public bool IsReusable
        {
            get
            {
                return true;
            }
        }
    }
}